package com.mingqijia.gassafety.authority.dal.provider;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mingqijia.gassafety.authority.dal.command.CreateRoleCommand;
import com.mingqijia.gassafety.authority.dal.command.QueryRoleCommand;
import com.mingqijia.gassafety.authority.dal.command.RemoveRoleCommand;
import com.mingqijia.gassafety.authority.dal.command.UpdateRoleCommand;
import com.mingqijia.gassafety.authority.dal.handler.RoleTranslator;
import com.mingqijia.gassafety.db.entity.auth.RoleEntry;
import com.mingqijia.gassafety.db.mapper.auth.RoleMapper;
import com.mingqijia.gassafety.shared.constant.Constants;
import com.mingqijia.gassafety.shared.cqrs.QueryHandler;
import com.mingqijia.gassafety.shared.enums.RoleType;
import com.mingqijia.gassafety.shared.enums.RunningState;
import com.mingqijia.gassafety.shared.enums.YesNoEnum;
import com.mingqijia.gassafety.shared.utils.ApplicationUtils;
import com.mingqijia.gassafety.shared.handler.GlobalAuthenticationException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 信息CU操作(C-create,U-update)
 * @author Damon S.
 * @version v0.2
 * @date 2021-06-19
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RoleProvider extends ServiceImpl<RoleMapper, RoleEntry> implements QueryHandler<RoleEntry> {

    private final RoleTranslator translator;

    /** 查询当前 spId 下的所有有效角色 */
    public Page<RoleEntry> find(QueryRoleCommand command) {
        LambdaQueryWrapper<RoleEntry> queryClause = new LambdaQueryWrapper<>();
        Optional.ofNullable(command.getName()).ifPresent(
                name -> queryClause.like(RoleEntry::getName, name)
        );
        if (Objects.nonNull(command.getState()) && !RunningState.NA.equals(command.getState())) {
            queryClause.eq(RoleEntry::getState, command.getState().getCode());
        }
        queryClause.eq(RoleEntry::getIsDeleted, YesNoEnum.N.getCode())
                .eq(RoleEntry::getSpId, ApplicationUtils.getHeaderSpId())
                .orderByDesc(RoleEntry::getCreatedAt);
        return this.page(createPage(command), queryClause);
    }

    public RoleEntry findRoleByIdOrName(String roleIdOrName) {
        QueryWrapper<RoleEntry> queryClause = new QueryWrapper<>();
        queryClause.lambda().eq(RoleEntry::getId, roleIdOrName)
                .or().like(RoleEntry::getName, roleIdOrName);
        return this.getOne(queryClause);
    }

    public List<RoleEntry> findValidRoles(List<String> roleIds) {
        List<RoleEntry> entries = listByIds(roleIds);
        if (CollectionUtils.isEmpty(entries)) {
            return Collections.emptyList();
        }
        return entries.stream().filter(
                entry -> Objects.equals(RunningState.RUNNING.getCode(), entry.getState()) && !entry.getIsDeleted()
        ).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    public String create(CreateRoleCommand command) {
        this.attachOperator2Command(command);

        QueryWrapper<RoleEntry> queryClause = new QueryWrapper<>();
        queryClause.lambda().eq(RoleEntry::getSpId, command.getSpId())
                .eq(RoleEntry::getName, command.getName())
                .eq(RoleEntry::getIsDeleted, YesNoEnum.N.getCode());

        if (!Objects.equals(Constants.INT_ZERO, this.count(queryClause))) {
            throw new GlobalAuthenticationException("角色名已存在");
        }
        RoleEntry entry = translator.toEntry(command);
        entry.setType(RoleType.ADMIN.getCode());
        entry.setState(RunningState.RUNNING.getCode());

        if (!this.save(entry)) {
            throw new GlobalAuthenticationException("创建角色失败");
        }
        return entry.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean update(UpdateRoleCommand command) {
        this.attachOperator2Command(command);

        UpdateWrapper<RoleEntry> updateClause = new UpdateWrapper<>();
        updateClause.lambda().eq(RoleEntry::getId, command.getId());

        RoleEntry entry = translator.toEntry(command);
        return this.update(entry, updateClause);
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean remove(RemoveRoleCommand command) {
        this.attachOperator2Command(command);

        UpdateWrapper<RoleEntry> updateClause = new UpdateWrapper<>();
        updateClause.lambda().in(RoleEntry::getId, command.getUserIds())
                .ne(RoleEntry::getId, Constants.PLATFORM_SR);

        RoleEntry entry = translator.toEntry(command);
        entry.setIsDeleted(YesNoEnum.Y.isFlag());

        return this.update(entry, updateClause);
    }
}
